// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package file

import (
	"fmt"
	"gitee.com/go-wares/log/base"
	"gitee.com/go-wares/log/conf"
)

// Formatter
// is a component that convert log item to string.
type Formatter struct{}

// Format
// log item as string.
func (o *Formatter) Format(item *base.Item) (body []byte) {
	if conf.Get().FileAdapter.Json {
		return o.json(item)
	}
	return o.body(item)
}

// +---------------------------------------------------------------------------+
// | Access methods                                                            |
// +---------------------------------------------------------------------------+

func (o *Formatter) body(item *base.Item) []byte {
	c := conf.Get()

	// Prefix.
	//
	//  - time
	//  - level
	str := fmt.Sprintf(`[%s][%s][service-name=%s][service-version=%s]`,
		item.Time.Format(c.TimeFormat),
		item.Level,
		c.ServiceName,
		c.ServiceVersion,
	)

	// Append
	// opentracing fields.
	if item.TraceId != nil {
		// trace-id.
		str += fmt.Sprintf(`[trace-id=%s]`, item.TraceId)

		// parent span id and position.
		if item.ParentSpanId != nil {
			str += fmt.Sprintf(`[parent-span-id=%s][parent-span-position=%d]`,
				item.ParentSpanId,
				item.ParentSpanPosition,
			)
		}

		// current span id and position.
		if item.SpanId != nil {
			str += fmt.Sprintf(`[span-id=%s][span-position=%d]`,
				item.SpanId,
				item.SpanPosition,
			)
		}
	}

	// Append
	// key/value pairs.
	if item.Field != nil {
		str += " " + item.JsonField()
	}

	// Append
	// log message content.
	str += " " + item.Text

	// Append
	// debug backtrace.
	if item.Level.IsFatal() && item.Stack != nil {
		str += fmt.Sprintf("\n%s", item.Stack.String())
	}
	return []byte(str)
}

func (o *Formatter) json(item *base.Item) []byte {
	if body, err := (&Entity{}).Init(item).Byte(); err == nil {
		return body
	}
	return nil
}
